#ifndef ODN_MODELENTITY_H
#define ODN_MODELENTITY_H

#include <opal\opal.h>
#include <ogre\Ogre.h>

#include "ODN_ModelBit.h"
#include "ODN_BaseEntity.h"
#include "ODN_Maths.h"
#include "ODN_Containers.h"
#include "ODN_Events.h"

namespace ouden {

class ODN_DLLACCESS CModelEntity;



//////////Events///////////

class ODN_DLLACCESS CBreakEvent : public CServerEvent
{
public:
	CBreakEvent(CModelEntity* pEntity) : m_pEntity(pEntity) 		{}
protected:	
	virtual void onActivate();
	virtual void onSend() 		{ /*TODO: Code to encode event data into packet and send over network*/ }
	virtual void onReceive(Packet* pPacket) 	{ /*TODO: Code to decode a network packet into event data*/ }
private:
	CModelEntity* m_pEntity;
};

class ODN_DLLACCESS C_StartMoveEvent : public C_ClientEvent
{
public:
	C_StartMoveEvent(CModelEntity* pEntity, Vector vDirection) : m_pEntity(pEntity), m_vDirection(vDirection) 		{}
protected:	
	virtual void onActivate();
	virtual void onSend() 		{ /*TODO: Code to encode event data into packet and send over network*/ }
	virtual void onReceive(Packet* pPacket) 	{ /*TODO: Code to decode a network packet into event data*/ }
private:
	CModelEntity* m_pEntity;
	Vector m_vDirection;
};

class ODN_DLLACCESS C_EndMoveEvent : public C_ClientEvent
{
public:
	C_EndMoveEvent(CModelEntity* pEntity, Vector vDirection) : m_pEntity(pEntity), m_vDirection(vDirection) 		{}
protected:	
	virtual void onActivate();
	virtual void onSend() 		{ /*TODO: Code to encode event data into packet and send over network*/ }
	virtual void onReceive(Packet* pPacket) 	{ /*TODO: Code to decode a network packet into event data*/ }
private:
	CModelEntity* m_pEntity;
	Vector m_vDirection;
};

//////End of Events////////



class ODN_DLLACCESS CModelEntity : public CBaseEntity
{
	public:

        DECLARE_ENTITY_CLASS(CModelEntity);

        CModelEntity() : CBaseEntity("Crapname") {} // CRAP
        CModelEntity(String sName);
		CModelEntity(String sName, String sModelName);
		virtual ~CModelEntity();
		
		//////////////////////////
		friend class CBreakEvent;
		//TODO: Think about the need for client and server versions of client
		// events and their functions
		friend class C_StartMoveEvent;
		friend class C_EndMoveEvent;
		//////////////////////////
		
		void loadModel(String sName);
		
		//Event handling functions
		virtual void onBreak() 		{}// = 0;
		virtual void onStartMove(Vector vDirection) 		{}// = 0;
		virtual void onEndMove(Vector vDirection) 		{}// = 0;
		
		virtual void update();
		
		//TODO: Consider allowing multiple Ogre entities for a single ModelEntity, but probly not
		
		void addBit(CModelBit* bit) 		{ m_pBits.push_back(bit); }
		//void addOgreEntity(Ogre::Entity* ent) 		{ m_pOgreEntities.push_back(ent); }

		void changeAnimState(String newState) { m_pCurrentAnimState = m_pOgreEntity->getAnimationState(newState); }

		// TODO: think how do these work with jetpacking?
		enum SimulationState { ANIMATING, BLENDING, RAGDOLLING };
		void changeSimState(SimulationState newState);

        //CRAP probably
		
		//TODO: REMOVE CModelBit* getRootBit() { return m_pRootBit; }
		//TODO: Add the following Opal wrapping functions: 
		//TODO: Think about possibly adding these functions to modelbit as well to access directly, so that they can be used on a specified bit if required
		Vector 	getPos() 		 		{ return toOudenVector(m_pBits[0]->getSolid()->getPosition()); } 	//Returns position of the root bit
		void 	setPos(Vector vPos) 	{ m_pBits[0]->getSolid()->setPosition(toOpalPoint(vPos)); }
		/*Quaternion getOrientation() 	{ return toOudenQuaternion(m_pRootBit->getSolid()->getQuaternion()); } 	//Returns the orientation of the root bit
		void 	setOrientation(Quaternion qQuat) 	{ m_pRootBit->getSolid()->setQuaternion(toOpalQuaternion(qQuat)); }
		*///setStatic(); 		//Set whether the root bit is physically static, ie. immovable
		//isStatic(); 		//Returns whether the root bit is physically static
		//addForce(Vector vForce, Vector vPos, Scalar fDuration, Type/*?*/); 		//Apply a force to the root node
		//getMass(); 		//Returns the mass of the root bit
		//setMass(); 		//Sets the mass of the root bit
		//More as needed... 
		
		//Ogre::Node* getNode() { return m_pRootBit->getNode(); }
        opal::Solid* getSolid() { return m_pBits[0]->getSolid(); }
        //opal::Solid* getSolid(int num) { return m_pRootBit->getChild(num)->getSolid(); }
		Ogre::Entity* 		getOgreEntity() 	{ return m_pOgreEntity; }

	protected:

        Array<CModelBit*> m_pBits;
		
		//TODO: REMOVE CModelBit* m_pRootBit;
		Ogre::Entity* m_pOgreEntity;
		Ogre::AnimationState* m_pCurrentAnimState;

		SimulationState simState;

	private:

};

} //namespace ouden

#endif // ODN_MODELENTITY_H
